实践篇03--Spring Cloud Eureka
Spring Cloud Eureka
是Spring Cloud Netflix
微服务套件中的一部分,它基于Netflix Eureka
的二次封装,主要是负责完成微服务架构的服务治理能力。我们只需通过简单引入依赖和注解配置就能使Spring Boot
构建的微服务应用轻松地与Eureka服务治理体系进行整合。下面将构建用于服务治理的基础设施:
- 构建服务注册中心
- 服务注册与服务发现
- Eureka的基础架构
- Eureka的服务治理机制
- Eureka的配置
服务治理
服务治理是微服务架构中最为核心和基础的模块,主要用于实现各个微服务实例的自动化注册与发现。随着业务的发展、功能的复杂、微服务应用的增加,静态配置维护难度会递增,且面对不断发展的业务,集群规模、服务位置和命名都有可能改变,手工维护的方式容易导致错误和冲突。
因此为了解决微服务架构中实例维护问题,出现了许多服务治理框架和产品,他们的实现主要都围绕着服务注册与服务发现机制来实现对微服务应用实例的自动化管理。
- 服务注册:在服务治理框架中,会构建一个注册中心,每个服务向注册中心登记自己提供的服务,将主机、端口号、通信协议等信息告知。注册中心会在服务启动和注册后,维护一个服务清单,并以心跳的方式检测清单中的服务是否可用,若不可用则剔除,以达到排除故障的效果。
- 服务发现:由于在服务治理框架下运作,服务间的调用不再通过指定具体的实例地址来发现,而是通过向服务名发起请求调用实现。所以,服务调用放在调用服务提供方接口时,并不知道具体的服务实例位置。因此调用发需要向服务注册中心咨询服务,并获取所有的服务的实例清单,以实现对具体服务实例的访问。
Netflix Eureka
Spring Cloud Eureka
,使用Netflix Eureka
实现服务注册与发现,既包含服务端组件,也包含客户端组件,提供了完备的RESTful API,支持将非Java语言构建的微服务纳入其服务治理体系中。
Eureka服务端,也称为服务注册中心,支持高可用配置,依托于强一致性提供良好的服务实例可用性,可以应对多重不同的故障场景。当Eureka以集群模式部署,集群中有分片出现故障时,Eureka会转入自动保护模式。它允许分片故障期间继续提供服务的发现和注册,当故障分片回复运行时,集群中其它分片会它们的状态再次同步回来。
Eureka客户端,主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入到客户端应用程序的代码中,当应用程序运行时,客户端向注册中心注册自身的提供的服务,并周期性地发送心跳来更新它的服务租约。同时它也能从服务端查询当前注册的服务信息并将它们缓存到本地并周期地刷新服务状态。
搭建服务注册中心
创建一个Spring Boot工程enreka-server
,在pom.xml
中引入相关依赖:
"1.0" encoding="UTF-8"
xml version=<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
</properties>
<!-- eureka服务依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在项目启动器中添加@EnableEurekaServer
注解启动一个服务注册中心提供给其他应用进行对话。
package com.example.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
默认情况下,该服务注册中心也会将自己作为客户端进行注册。可在配置文件application.yml
中禁用该项:
spring:
application:
name: Eureka-Server
server:
port: 10000
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false # 不向注册中心注册自己
fetch-registry: false # 注册中心的职责是维护服务实例,不需要检索服务
启动应用,并访问http://localhost:10000
,界面如下:
此时可见Instances currently registered with Eureka
为空,这是因为还没有服务向注册中心注册。
构建服务
接下来构建一个微服务向服务中心注册自己。新建Spring Boot项目eureka-client
,在pom.xml
添加依赖:
"1.0" encoding="UTF-8"
xml version=<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>eureka-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-client</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<!-- 添加Eureka依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
添加/hello
接口,通过注入DiscoveryClient
对象,在日志中输出服务的相关信息。
package com.example.eurekaclient;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Yov
* @date 2018/1/14 20:10
*/
public class IndexController {
private final Logger logger = Logger.getLogger(getClass());
private DiscoveryClient discoveryClient; // 用于获取服务
("/hello")
public String index() {
discoveryClient.getServices().forEach(id -> {
discoveryClient.getInstances(id).forEach(instance -> {
// 在日志中输出服务的相关信息
logger.info("Hello, host:" + instance.getHost() +
", server_id: " + instance.getServiceId());
});
});
return "Hello World!";
}
}
在程序入口添加@EnableDiscoveryClient
注解,激活Eureka中的DiscoveryClient
(自动化配置,创建DiscoveryClient
接口针对Eureka的EnrekaDiscoveryClient
实例),这样才能实现Controller中对服务信息的输出。
package com.example.eurekaclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
修改配置文件application.yml
spring:
application:
name: hello-service # 为服务命名
eureka:
client:
service-url:
defaultZone: http://localhost:10000/eureka # 为服务指定注册中心
server:
port: 10001
启动服务后,可以在eureka-client
控制台看到如下信息:
Registering application hello-service with eureka with status UP
Saw local status change event StatusChangeEvent [timestamp=1516155585227, current=UP, previous=STARTING]
DiscoveryClient_HELLO-SERVICE/youw:hello-service:10001: registering service...
DiscoveryClient_HELLO-SERVICE/youw:hello-service:10001 - registration status: 204
Tomcat started on port(s): 10001 (http)
Updating port to 10001
当访问该服务时,会出现控制台输出如下信息:Hello, host:youw, server_id: HELLO-SERVICE
。
在eureka-server
控制台可看到如下信息:Registered instance HELLO-SERVICE/youw:hello-service:10001 with status UP (replication=false)
。访问http://localhost:10000
,此时可见Instances currently registered with Eureka
为增加了一个服务:HELLO-SERVICE
。
高可用注册中心
在微服务这样分布式的环境中,需要充分考虑发生故障的情况,所以在生产环节需要对各个组件进行高可用部署。Eureka Server充分考虑了这一点,每一个节点既可以是服务提供者,也可以是服务消费者。服务注册中心也可以向其他服务注册自身。
新建一个项目eureka-center
,作为另一个服务注册中心,参照enreka-server
,但要修改application.qml
文件:
server:
port: 20000
spring:
application:
name: eureka-server
eureka:
instance:
hostname: center
client:
service-url:
defaultZone: http://localhost:10000/eureka/ # 指向注册中心
修改eureka-server
的application.yml
启动:
spring:
application:
name: eureka-Server
server:
port: 10000
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://center:20000/eureka/ # 指向注册中心
修改eureka-client
的application.yml
spring:
application:
name: hello-service # 为服务命名
eureka:
client:
service-url:
# 同时向两个注册中心注册自己
defaultZone: http://localhost:10000/eureka/,http://center:20000/eureka/
server:
port: 10001
其实启动三个应用程序,访问两个注册中心,均能看到:
此时两个注册中心即使有一个中断了,在另一个注册中心的服务依然可以访问hello-server
。
This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:http://yov.oschina.io/article/微服务/Micro Service/实践篇03--Spring Cloud Eureka/